<?php

function read_images($filename, $type = 'jpeg')
{
    switch ($type) {
        case 'jpeg':
            $i = imagecreatefromjpeg($filename);
            break;
        case 'png':
            $i = imagecreatefrompng($filename);
            break;
        default:
            echo '图片格式不认识!!!';
            exit(1);
    }
    $w = imagesx($i);
    $h = imagesy($i);
    return [$i, $w, $h];
}


// 二值图
function black_image($gd_resource)
{
    $w = imagesx($gd_resource);
    $h = imagesy($gd_resource);

    $canvas= imagecreatetruecolor($w, $h);
    $black = imagecolorallocate($canvas, 0, 0, 0);
    $white = imagecolorallocate($canvas, 255, 255, 255);


    $isBlack = function ($rgb) {
        static $limit = ['r' => 180, 'g' => 150, 'b' => 256];
        return ($rgb['r'] < $limit['r'] 
                && $rgb['g'] < $limit['g'] 
                && $rgb['b'] < $limit['b']);
    };

    $getRGB = function ($gd_resource, $i, $j) {
        $rgb = imagecolorat($gd_resource, $i, $j);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;
        return ['r'=>$r, 'g'=>$g, 'b'=>$b];
    };

    for ($i=0; $i<$w; $i++) {

        for ($j=0; $j<$h; $j++) {

            if ($isBlack($getRGB($gd_resource, $i, $j))) {
                imagesetpixel($canvas, $i, $j, $black);
            } else {
                imagesetpixel($canvas, $i, $j, $white);
            }

        }
    }
    
    return $canvas;
}


function point_puzzle($puzzle)
{
    list($pres, $pw, $ph) = read_images($puzzle, 'png');

    $opaque = function(&$res, $x, $y, $diff = 21){
        $rgb = imagecolorat($res, $x, $y);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;
        return ($r == 0 && $g == 0 && $b == 0);
    };

    $isBorder= function(&$res, $x, $y, $diff = 30) use ($pw, $ph, $opaque) {
        if ($x < 2 || $y < 2 || $x > $pw-2 || $y >= $ph-2)
            return false;

        $rgb = imagecolorat($res, $x, $y);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;
        return (abs($r-200) < $diff 
            &&  abs($g-200) < $diff 
            &&  abs($b-200) < $diff);
    };

    $isPoint = function(&$res, $x, $y) use ($pw, $ph, $opaque) {
        if ($x < 2 || $y < 2 || $x > $pw-2 || $y >= $ph-2)
            return false;

        $rgb = imagecolorat($res, $x, $y);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;
        return ($r != 0 || $g != 0 || $b != 0);
    };


    $list = [];
    $minx = $pw;
    $miny = $ph;
    $first= null;
    for ($x=0; $x < $pw; $x++) { 
        for ($y=0; $y < $ph; $y++) { 

            // 不是透明点,不管
            if (!$isPoint($pres, $x, $y)) 
                continue;

            // 记录坐标
            if (empty($first)) {
                $ty = $y;
                $count = 0;
                do {
                    $count++;
                } while ($isBorder($pres, $x, $ty++));

                if ($count >= 20)
                    $first = [$x,$y];
            }

            $list[] = [$x, $y];
            if ($x < $minx) $minx = $x;
            if ($y < $miny) $miny = $y;
        }
    }

    // 偏移计算
    foreach ($list as &$point) {
        list($x, $y) = $point;
        $point = [($x - $minx), ($y - $miny)];
    }

    list($x, $y) = $first;
    $x = $x - $minx;
    $y = $y - $miny;
    return [$list, $x, $y];
}


function exec_img($big, $puzzle)
{
    list($bres, $bw, $bh) = read_images($big);
    list($list, $pw, $ph) = point_puzzle($puzzle);

    $isBlack = function(&$res, $x, $y){
        $rgb = imagecolorat($res, $x, $y);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;
        return ($r == 0 && $g == 0 && $b == 0);
    };

    $isPoint = function(&$res, $x, $y, $diff = 42){
        $rgb = imagecolorat($res, $x, $y);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;
        return (abs($r-200) < $diff
            && abs($g-200) < $diff
            && abs($b-200) < $diff);
    };

    $black = black_image($bres);

    for ($x=0; $x < $bw; $x++) { 

        for ($y=0; $y < $bh; $y++) {

            $temp = 0;
            while ($y < $bh && $isPoint($bres, $x, $y)) {
                $temp++;
                $y++;
            }

            if ($temp < 20) continue;

            $offsetX = $x;
            $offsetY = $y - $temp - $ph;
            $diff  = 0;
            $count = 0;
            $total = count($list);
            foreach ($list as $point) {
                list($px, $py) = $point;
                $px += $offsetX;
                $py += $offsetY;

                if ($py >= $bh || $px >= $bw)
                    break;

                if ($py < 0)
                    break;

                if ($isBlack($black, $px, $py) == false) {
                    $count++;
                    $diff = ($count/$total) * 100;
                    if ($diff > 10) 
                        break;
                }
            }

            // 
            if ($diff <= 10) {
                return $x;
            }
        }
    }
    return false;
}


function crop_images($page, $position, $path)
{
    list($x, $y, $w, $h) = $position;
    $res = imagecreatefrompng($page);
    $pw = imagesx($res);
    $ph = imagesy($res);

    $new   = imagecreatetruecolor($w, $h);
    for ($i=0; $i < $w; $i++) { 
        for ($j=0; $j < $h; $j++) { 
            $rgb = imagecolorat($res, $x+$i, $y+$j);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            
            $color = imagecolorallocate($new, $r, $g, $b);
            imagesetpixel($new, $i, $j, $color);
        }
    }
    imagepng($new, $path);
    imagedestroy($new);
}


// imagecolordeallocate
// crop_images('./images/page.png', , './images/big');